#pragma once

#include <iostream>
#include <cstring>
#include <cerrno>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "err.hpp"

namespace ns_client
{
    class TcpClient
    {
    public:
        TcpClient(std::string ip, uint16_t port)
            :ip_(ip)
            ,port_(port)
        {
            std::cout << ip_ << ":" << port_ << std::endl;
        }

        ~TcpClient()
        {}

        void InitClient()
        {
            //创建套接字
            sock_ = socket(AF_INET, SOCK_STREAM, 0);
            if (sock_ == -1)
            {
                std::cerr << "Create Sock Fail: " << strerror(errno) << std::endl;
                exit(SOCKET_ERR);
            }

            // 初始化服务端addr信息
            memset(&server_, 0, sizeof server_);
            server_.sin_family = AF_INET;
            server_.sin_port = htons(port_);
            server_.sin_addr.s_addr = inet_addr(ip_.c_str());

            std::cout << "socket success!" << std::endl;
        }

        void service()
        {
            //流式传输
            char buff[1024];
            while(true)
            {
                std::string msg;
                std::cout << "Please Enter>>";
                std::getline(std::cin, msg);

                write(sock_, msg.c_str(), msg.size());


                int n = read(sock_, buff, sizeof(buff) - 1);
                if(n > 0) buff[n] = '\0';
                else continue;

                //打印信息
                std::string ip = inet_ntoa(server_.sin_addr);
                uint16_t port = ntohs(server_.sin_port);
                std::cout << "Server [" << ip << "-" << port << "] >> " << buff << std::endl;
            }
        }

        void StartClient()
        {
            //尝试与服务端建立链接
            int n = 5;
            while(n)
            {
                if(connect(sock_, (struct sockaddr*)&server_, sizeof server_) == -1)
                    std::cerr << "服务器连接失败，正在重试: " << n-- << std::endl;
                else
                    break;
                
                sleep(1);
            }

            if(n == 0)
            {
                std::cerr << "Connect Fail! " << strerror(errno) << std::endl;
                exit(CONNECT_ERR);
            }

            service();  //启动服务
        }

    private:
        int sock_;  //套接字
        std::string ip_;
        uint16_t port_;
        struct sockaddr_in server_;
    };
}